#include "DHT11.h"

// DHT11 引脚定义
#define DHT11_PORT GPIOA
#define DHT11_PIN  GPIO_Pin_3



static void DHT11_SetPinOutput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 推挽输出
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

// 配置 GPIO 为输入模式
static void DHT11_SetPinInput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; // 输入模式
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

// 初始化 GPIO 引脚
void DHT11_Init(void) {
    DHT11_SetPinOutput(); // 初始状态设置为输出
    GPIO_WriteBit(DHT11_PORT, DHT11_PIN, Bit_SET); // 拉高
}

// 发送起始信号
static void DHT11_StartSignal(void) {
    DHT11_SetPinOutput();                         // 配置为输出模式
    
    GPIO_WriteBit(DHT11_PORT, DHT11_PIN, Bit_RESET); // 拉高 // 拉低
                                 // 延时至少 18ms
    delay_ms(18); 
    GPIO_WriteBit(DHT11_PORT, DHT11_PIN, Bit_SET); // 拉高   // 拉高
    delay_us(20);                           // 延时 20us
    DHT11_SetPinInput();                          // 切换为输入模式
}

// 检测 DHT11 响应信号
static uint8_t DHT11_CheckResponse(void) {
    uint8_t response = 0;
    delay_us(40); 																			// 等待 40us
    if (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 检测低电平
        delay_us(80);
        if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 检测高电平
            response = 1;
        }
        while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)); // 等待结束
    }
    return response;
}

// 读取一个字节（8bit）
static uint8_t DHT11_ReadByte(void) {
    uint8_t i, data = 0;
    for (i = 0; i < 8; i++) {
        while (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)); // 等待高电平
        delay_us(40);                              // 等待 40us
        if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) {   // 如果是高电平
            data |= (1 << (7 - i));                      // 记录 1
        }
        while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)); // 等待低电平
    }
    return data;
}

// 读取温湿度数据
uint8_t DHT11_Read(DHT11_DataTypeDef *data) {
    uint8_t buffer[5] = {0};
    uint8_t checksum;

    DHT11_StartSignal();       // 发送起始信号
    if (DHT11_CheckResponse()) { // 检测响应信号
        for (int i = 0; i < 5; i++) {
            buffer[i] = DHT11_ReadByte(); // 读取 5 字节数据
        }
        checksum = buffer[0] + buffer[1] + buffer[2] + buffer[3];
        if (checksum == buffer[4]) { // 校验通过
            data->humidity = buffer[0];
            data->temperature = buffer[2];
            return 1; // 数据读取成功
        }
    }
    return 0; // 数据读取失败
}
